gius tech and non-tech scratchings

My definition of "Good Code"

(This is a writeup of a lightning talk I gave about a year ago, and its become only more useful to me in the months since.)

Back in 200BC or thereabouts the world was gifted Peter Naur's paper titled "Programming as Theory-Building" which, if you'll permit my reductiveness, presented the idea that "programs" are primarily the abstract "theories" within programmers' heads and programmers' heads alone, with code and other documentation as byproducts of these theories. The paper reinforces this idea properly but for my purposes I appeal only to the intuition (hopefully felt by most programmers) that the best way to get to grips with a codebase is to talk to the people what wrote it, because reading the code can be a slow and demeaning affair.

I paraphrase the paper to define 'theory-building' as the process of forming and refining a program theory; this is an abstract activity which may involve producing text but in that case the text is a means and the theory is the end. Further, I define 'compression' as the process of turning a theory into text (code, documentation, keynotes, whatever), and 'uncompression' as the process of rebuilding a theory from compressed text. These processes are skills to be honed, and a programmer ought to be comfortable doing all three.

The paper claims that program theories are "inextricably bound to human beings", which in other words is that compression is necessarily a lossy process. A programmer working on a codebase they didn't write, working without access to those that did write it, will therefore uncompress the text into a new theory; their theory might still be useful, or perhaps less so, but it will be different. The mismatch between text and theory results in 'program decay', where modifications consistent with the new theory but inconsistent with the old are made to the code. Program decay is self-encouraging because a more decayed codebase won't uncompress sensibly for the next programmer, and their theory will likely be even more inconsistent, and their modifications will produce more decay still. The paper concludes that such a codebase needs not better code but a better theory, and that better theory demands a new compression — a rewrite.

Eight years in to my career, I've seen (and participated in) this practice enough to know how useful this framework is for identifying and explaining it. That said, I think the framework is due an update, because we've been busy for the last 2200 years or thereabouts and the world of software development has changed plenty. Specifically: I claim that theory compression isn't nearly as lossy as it once was. My language of choice and circumstance is Typescript, and Typescript grants me great power to declare trivially and unambiguously the purpose of individual lines of code. Labelled constant numbers have become enums, and enums have become string unions. Undivided walls of code have been partitioned into individual changes, and widespread conventions have been applied and misapplied to label, document, and verify these changes. Common behaviours have shrunk away into libraries which have coalesced into opinionated frameworks that specify what goes where and in what manner.

I won't pretend for a paragraph break that these changes have been unambiguously good, or helpful, or reliable, or any improvement at all; but they are all available now as destinations for parts of a compressed theory, and to an extent have become influences on the shapes of theories themselves: as I can use English to think, I can use Angular to theory-craft, and will use the form of its framework as the basis of the form of my theory. For me, this makes Angular a good framework: it is able to prescribe both form and structure of a program theory, and give me better theories as a result. I can somewhat rely on Angular to push back against me when I'm doing a wrong thing, and get out of my way when I'm doing a right thing. The same principle can apply to a library, or language, or convention, or individual linting rule: it's good if it can support and guide the theory-building required in that context.

I choose to believe without proof that any framework/library/language/convention/lint rule that can support theory-building is inherently able to assist in both the tasks of compression and uncompression; it's therefore possible to simplify the task of uncompression and give the next programmer the best chance of building a theory sufficiently consistent with the text (or, doing a 'successful uncompression'). The rest of the challenge remains with the programmer: they must be able to do the compression in order to build anything that runs, but they really ought to produce a text with the best chance of successful uncompression (or, text that 'uncompresses well'). This is what I think good code is: code that uncompresses well. It still won't be perfect — program decay is inevitable — but said decay can be stymied, and I think that's a worthy goal for any programmer.

A few more definitions come for free. Programmers also need to compress theories (or 'write code') and a theory that 'compresses well' is one that affords the programmer the least agony. As above, this is also affected by framework/language choice; in cases where you can choose, a 'good language for a given theory' is one that allows good compression. For a given framework/language, a good theory is one that both meets all the requirements (mustn't forget that...) and compresses well given that context.

A good programmer is able to build good theories, compress theories well, and uncompress text well. Note that all of this is very much dependent on context: uncompression matters little for short-lived tools; unsound requirements can destroy any hope of building a good theory; fast-paced environments often require a fast and inaccurate decompression over a slower consistent one because program decay costs less than missing a crucial moment.

Now, with all that said, it's not lost on me that the relevance of the 'good programmer' will be somewhat diminished for those who have offloaded the tasks of compression and uncompression (and, let's be honest, likely most of the theory-building too) to some LLM. There must be something it means to be a good programmer in that environment, or, for that matter, a bad programmer. I might even work it out eventually, but I haven't yet, so I stop here.

home